fix(dispatch-gates): mask # comments on shell-kind sources, so a shell target's inherited population is not prose - #16740
Merged
baozhoutao merged 4 commits intoSep 8, 2026
Conversation
…ell-comment-mask-watch-hints
…ell target's inherited population is not prose `extractWatchHints` masked its source with `maskedModuleBody`, which understands every comment syntax JavaScript has. `PROGRAM_TEXT_TARGET` admits a third file kind, `.sh`, whose prose is none of them: every path a `#` comment mentioned came back as a watch hint, because the JS-shaped literal regex reads a backticked path as a template literal and a double-quoted one as a string. The mask is kind-scoped and composes ONTO the JS mask rather than replacing it, so the shell hint set is a subset of today's by construction. Quote state is line-scoped: a cross-line scanner desyncs on command substitution and on a `<<<` here-string, and one unbalanced quote then disables the mask for the rest of the file — the fabricating direction. The residue is a bounded over-mask. Measured over the 27 tracked `.sh` files: 37 hints as spelled, 8 after the mask. Tree-wide over 6,361 scanned files: 11 changed, 11 shrank, 0 grew. The live derivation is byte-identical, because no family-to-`.sh` population edge exists yet. Claude-Session: https://claude.ai/code/session_012GKcPZbMoGq7WPzKLfRBTU Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Sep 8, 2026
baozhoutao
marked this pull request as ready for review
September 8, 2026 03:18
baozhoutao
enabled auto-merge
September 8, 2026 03:18
baozhoutao
deleted the
claude/issue-16132-shell-comment-mask-watch-hints
branch
September 8, 2026 03:40
This was referenced Sep 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #16132
extractWatchHintsmasked its source withmaskedModuleBody, which understandsline comments, block comments and a shebang — every comment syntax JavaScript
has.
PROGRAM_TEXT_TARGETadmits a third file kind,.sh, and a shell script'sprose is none of those three: on a shell-kind source every path a
#commentmentioned came back as a watch hint, because the JS-shaped literal regex reads a
backticked path in prose as a template literal and a double-quoted one as a
string.
Nothing widens. The instrument reports fewer hints on shell-kind sources and
the same hints everywhere else.
The card's fixture table, driven
All four against
scripts/fixture.sh, on this branch:The card's own
node -ecriterion printsNOT CALIBRATEDonbe92d46andCALIBRATEDhere.Why a per-line recogniser, and why the composition order is measured
A
#opens a comment only at the start of a word and only outside quotes, so$#,${#a},a#band a#inside'…'or"…"are not comment starts — ablank-from-
#-to-end-of-line pass corrupts exactly the lines worth reading.Quote tracking is therefore real, and it is where being wrong is unbounded: one
unbalanced quote silently disables the mask for the whole rest of the file, which
is the fabricating direction.
A cross-line scanner cannot keep shell's quoting straight. One was built and
measured on this tree before this one — with here-doc tracking and here-string
handling — and it still left 1,467 comment lines unmasked in
scripts/pm/os-verify-lock.shand 8 inscripts/release-spec-changes.sh,where the two surviving hints were the prose ones this card is about. The causes
were ordinary shell: command substitution restarts quoting, so
"$(printf '%s' "$x")"reads as three spans to a scanner that does not model$( … ); and ahere-string (three less-than signs) looks like a here-doc introducer to anything
that matches the two-less-than form first.
So quote state is line-scoped: it opens and dies on its own line. Every
misreading is then bounded to the line it is on, and the residue lands in the
over-masking direction — a
#line inside a here-doc body or a multi-linequoted string is masked as if it were a comment. That is a missing lead on text
that is data rather than a path the script opens, which is the direction this
file errs in everywhere. It is pinned as a deliberate case so nobody "repairs" it
back into carried state.
The composition order is measured too, and it is the one that cannot widen.
Masking
#first stops a#comment containing@objectstack/*from openinga phantom JS block comment, which uncovers code below it and adds hints —
2 on this tree (
scripts/downstream-smoke.sh,.claude/hooks/guard-tree-enum.sh).Masking
#last can only blank more of an already-masked body, so the shellhint set is a subset of today's by construction.
The kind predicate is spelled as the difference of the two tests that already
exist —
PROGRAM_TEXT_TARGETminusSCANNED_SOURCE_EXTENSIONS— rather than asa third list, so a kind added to the follow arrives already masked: the widening
that admits it is the same edit that routes it here.
Blast radius, re-measured on
be92d46The card's numbers were taken on
1f2a02b. Re-measured on today's tree:1f2a02b)be92d46).shfiles#maskscripts/bump-objectui.shTree-wide, over the 6,361 scanned program-text files: 11 files changed,
11 shrank, 0 grew; 6,885 → 6,856 hints. Every changed file is a
.sh.--jsonderivations for five shell-file surfaces (bump-objectui.sh,vercel-ignore-docs.sh,pm/ensure-pm-labels.sh,.claude/hooks/guard-governed-enqueue.sh,collect-release-notes.sh) arebyte-identical between
be92d46and this branch — today's output really isunchanged, because 0 family-to-
.shpopulation edges exist. This lands beforethe card that would create the first one.
scripts/bump-objectui.shreaching 0 is correct, and the reason is not the maskThe dispatch brief carried an assumption that 0 here is a red flag, because
.changeset/*.mdhas a genuine code site. The genuine site is real, and it wasalready invisible to this scan before this change:
extractWatchHintsadmits a literal only if it matches^[\w.@], and this onebegins with
${. Measured onbe92d46, that line alone yields[]; the sameline without the parameter expansion yields
.changeset/console-x.md. So thefile's true population is non-empty and the scan correctly reports none of it —
a missing lead produced by a pre-existing admission rule, not by the mask. All
seven hints the file used to report were prose.
Tests
node scripts/pm/dispatch-gates.mjs --self-test— 1552 cases pass, 18 ofthem new.
Ablation (one-time, run at
4bbf141; the only commit after it is four linesof docblock prose): the wiring in
extractWatchHintswas mutated tofalse && hashCommentProgram(scriptPath). The mutation was proved to reach diskby blob hash (
35bf7de8→59507bda) and by an anchor grep (removed 1 → 0,injected 0 → 1) — not by an editor's exit code, which is 0 on zero matches. Under
it the card's criterion prints
NOT CALIBRATEDand the self-test exits 1 with9 of the new cases red, including the live sweep, which then reads
37 spelled without it, 37 with. Restored withgit checkout HEAD --naming thefile — never the bare
git checkout --form, which takes the mutation straightback out of the index — and verified by the blob hash returning to
35bf7de8with
git diff HEADempty, not by the restore command's exit code.Gates. Derived from the actual changed set with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands(no staleness warning;
--repoholds against this checkout's remote). The samederivation run from a clean
origin/maincheckout as a control returns abyte-identical 30-command list, so editing the tool did not move its own
answer. All 30 ran green — exit codes written to disk as each finished — and
--ranreconciles atb729acf: 30 derived, 30 run, 0 NOT-MEASURED, 0 UNRUN.No changeset:
scripts/pm/**publishes nothing, and this workflow's own commentcalls a PR that edits a CI-internal script the textbook
skip-changesetcase.验收备注
Out of scope, filed as #16744 — a shell
#comment containing@objectstack/*opens a phantom JS block comment on a
.shsource, andmaskCommentsthenblanks every line down to the next terminator. Measured on this branch: 73,859
bytes of real shell code in
scripts/pm/os-verify-lock.sh, 17,482 inscripts/pm/os-regen-merge.sh, across 11 of the 27 tracked.shfiles; two livehints are lost to it, including the genuine
DEST="node_modules/@objectstack/spec/dist"inscripts/downstream-smoke.sh.It is the cheap direction (a missing lead, which this tool errs in on purpose),
it is a defect in the JS masker applied to shell rather than in the hint scan,
and its remedy is how the composition order this PR rejected adds its 2 hints —
so fixing it here is exactly the widening ruling 3 forbids.
scripts/bump-objectui.shis unaffected, checked because it is the file thatwould carry the first family-to-
.shedge.Generated by Claude Code